package com.xiashitech.agent.utils;

import com.xiashitech.agent.config.StartConfig;
import com.xiashitech.agent.instrumentation.base.context.TraceContextVars;
//import com.xiashitech.agent.instrumentation.base.context.bridge.BridgeBaggageBuilder;
import com.xiashitech.agent.instrumentation.context.BaggageIsModify;
import com.xiashitech.agent.instrumentation.context.InstContext;
import com.xiashitech.agent.instrumentation.redis.redisson.XSCompletableFuture;
import com.xiashitech.agent.instrumentation.utils.BaggageUtil;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.javaagent.shaded.io.opentelemetry.api.baggage.BaggageBuilder;
import ognl.Ognl;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class SessionUtil {

    /**
     * 判断baggage是否已获取到userid
     * @return
     */
    public static Boolean hasUserInBaggage(Baggage baggage) {
        if(baggage == null)
            baggage = Baggage.current();
        String userId = baggage.getEntryValue("xs.userId");
        return userId != null && !userId.isEmpty();
    }

    /**
     * 判断baggage是否已获取到userid
     * @return
     */
    public static Boolean hasUserInBaggage() {
        return hasUserInBaggage(null);
    }

    /**
     * 从session中获取用户id，通过ognl进行深度遍历
     * @param session
     * @return
     */
    public static Optional<String> getUseridFromSession(Object session, String attributePath) {
        if (session == null) {
            return Optional.empty();
        }

        Map<String,Object> sessionMap = new HashMap();
        try {
            Enumeration<String> attributeNames = (Enumeration<String>)session.getClass().getMethod("getAttributeNames").invoke(session);
            while (attributeNames.hasMoreElements()) {
                String sessionKey = attributeNames.nextElement();
                Object attribute = session.getClass().getMethod("getAttribute",new Class[]{String.class}).invoke(session,sessionKey);
                sessionMap.put(sessionKey,attribute);
            }
            if(sessionMap.size() == 0) {
                return Optional.empty();
            }
            Optional<Object> userid = Optional.empty();
            userid = Optional.ofNullable(Ognl.getValue(attributePath, sessionMap));
            return userid.map(oriUserid -> oriUserid.toString());
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将Object类型参数转换成byte[]类型，其中params为String类型或者其它对象类型
     * @param params
     * @return
     */
    public static byte[] convertObjectToByteArray(Object params) {
        if (params instanceof String) {
            return String.valueOf(params).getBytes();
        } else if(params instanceof byte[]) {
            return (byte[])params;
        } else {
            byte[] bytes = null;
            try (
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            ) {
                objectOutputStream.writeObject(params);
                objectOutputStream.flush();
                bytes = byteArrayOutputStream.toByteArray();
            } catch (Throwable e) {
                StartConfig.throwableStackPrinter(e);
            }
            return bytes;
        }
    }

    public static Baggage syncBaggage() {
        Baggage currentBaggage = Baggage.current();
        //System.out.println("###debug010 Sessionutil baggage"+currentBaggage.toString());
       //System.out.println("###debug010 Sessionutil baggage userId "+currentBaggage.getEntryValue("xs.userId"));
        //System.out.println("###debug010 Sessionutil baggage endpoint-api "+currentBaggage.getEntryValue("endpoint-api"));
        if(BaggageIsModify.getIsModify()) {
            System.out.println("###debug010 BaggageIsModify.getIsModify()");
            return currentBaggage;
        }
        try {
            BaggageBuilder currentBaggageBuilder = currentBaggage.toBuilder();
            XSCompletableFuture xsCompletableFuture = InstContext.getContext();
            if(xsCompletableFuture != null) {
                xsCompletableFuture.join();
                if(xsCompletableFuture.getRedisData() != null && xsCompletableFuture.getRedisData().getRedissonRequest() != null) {
                    Baggage preBaggage = xsCompletableFuture.getRedisData().getRedissonRequest().getBaggage();
                    preBaggage.forEach((key,value) -> {
                        System.out.println("###debug011 Sessunitls baggage key:"+key+"value:"+value);
                        currentBaggageBuilder.remove(key);
                        currentBaggageBuilder.put(key,value.getValue());
                        if(!BaggageIsModify.getIsModify()) {
                            BaggageIsModify.setIsModify(true);
                        }
                    });
                }
            }
            if(BaggageIsModify.getIsModify()) {
                Baggage afterBaggage = currentBaggageBuilder.build();
                TraceContextVars contextVars = TraceContextVars.get();
                afterBaggage.forEach((key,value) -> {
                    if (!"endpoint-api".equals(key))
                        contextVars.set(key,value.getValue());
                });
                InstContext.refreshCurrentThreadLocal();
                return afterBaggage;
            } {
                return currentBaggage;
            }
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
        return currentBaggage;
    }

    public static String getCookieValueByKey(Object request, String cookieKey) {
        String msid = null;
        try {
            Object[] cookies = (Object[])request.getClass().getMethod("getCookies").invoke(request);
            if(cookies == null) {
                return msid;
            }
            for (int i = 0; i < cookies.length; i++) {
                Object cookie = cookies[i];
                String key = (String)cookie.getClass().getMethod("getName").invoke(cookie);
                if(key.equalsIgnoreCase(cookieKey)){
                    Object value = cookie.getClass().getMethod("getValue").invoke(cookie);
                    if(value != null) {
                        msid = value.toString();
                    }
                }
            }
        } catch (Throwable e) {
            StartConfig.throwableStackPrinter(e);
        }
        return msid;
    }
}
